/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package skybash;

import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import lev.gui.LSaveFile;
import skybash.SkyBashSaveFile.GUISettings;
import skybash.gui.MainSettingsPanel;
import skybash.ini.INI;
import skyproc.*;
import skyproc.gui.*;

/**
 *
 * @author pc tech
 */
public class SkyBash implements SUM {

    //The main GUI class.
    SPDefaultGUI gui;
    //The language used for ASIS.
    public String ASISlanguage;
    //Container maps.
    Map<JCheckBox, Boolean> guiButtons = new HashMap<>();
    Map settingsMap;
    Map<String, String> modTags;
    //Stores a map of a mods tags with the mod.  Passed to merger classes via public.
    public HashMap<Mod, ModTags> mods = new HashMap<>();
    //Debug setting (from ini file).
    public boolean debug;
    //Stores the memory for the program, read from the ini and then restarts the program.
    public static int memory;
    //Stores the save file to store user settings on the disk.
    public static LSaveFile save = new SkyBashSaveFile();
    //Colors used in the GUI.
    static public Color blue = new Color(0, 147, 196);
    static public Color green = new Color(67, 162, 10);
    static public Color darkGreen = new Color(61, 128, 21);
    static public Color orange = new Color(247, 163, 52);
    static public Color yellow = new Color(255, 204, 26);
    static public Color lightGray = new Color(190, 190, 190);
    static public Color darkGray = new Color(110, 110, 110);
    //Fonts used in the GUI.
    static public Font settingsFont = new Font("Serif", Font.BOLD, 14);
    static public Font settingsFontSmall = new Font("Serif", Font.BOLD, 12);
    //The Main Menu panel for the background.
    public SPMainMenuPanel settingsMenu;
    //The main GUI panel for settings.
    public MainSettingsPanel mainSettingsPanel;
    // Version
    public String version = "0.11 Alpha";
    //Number of progress steps.  numSteps is overridden with the number of mods to parse.
    static int numSteps = 5;
    static int steps = 0;
    
    //Boss masterlist directory.
    String masterlist;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //ArrayList<String> arguments = new ArrayList<>(Arrays.asList(args));
        SkyBash main = new SkyBash();
        //main.processINI();

        //NiftyFunc used to allocate more memory.  Had a few issues, Java 7 allocates 1GB by default.
        /*
         * if (!arguments.contains("-nonew")) { try {
         * NiftyFunc.allocateMoreMemory("100m", "1024m", "SkyBash.jar",
         * "-nonew"); } catch ( IOException | InterruptedException ex) {
         * Logger.getLogger(SkyBash.class.getName()).log(Level.SEVERE, null,
         * ex); } }
         */

        SPGlobal.setGlobalPatch(main.getExportPatch());

        //Test for confirming max memory constraints.
        //System.out.println(Runtime.getRuntime().maxMemory());

        save.init();
        SUMGUI.open(new SkyBash());
    }

    @Override
    public String getName() {
        return "SkyBash";
    }

    @Override
    public ArrayList<GRUP_TYPE> importRequests() {
        ArrayList<GRUP_TYPE> type = new ArrayList<>();
        if (save.getBool(GUISettings.MERGE_NPCS)) {
            type.add(GRUP_TYPE.NPC_);
        }
        if (save.getBool(GUISettings.MERGE_WEAPONS)) {
            type.add(GRUP_TYPE.WEAP);
        }
        if (save.getBool(GUISettings.MERGE_RACES)) {
            type.add(GRUP_TYPE.RACE);
        }
        return type;
    }

    @Override
    public boolean importAtStart() {
        return false;
    }

    @Override
    public boolean hasStandardMenu() {
        return true;
    }

    @Override
    public SPMainMenuPanel getStandardMenu() {
        settingsMenu = new SPMainMenuPanel(blue);
        settingsMenu.setVersion(version, new Point(18, 16));

        mainSettingsPanel = new MainSettingsPanel(settingsMenu);
        settingsMenu.addMenu(mainSettingsPanel, true, save, GUISettings.SKYBASH_ON);
        return settingsMenu;
    }

    @Override
    public boolean hasCustomMenu() {
        return false;
    }

    @Override
    public boolean hasLogo() {
        return false;
    }

    @Override
    public URL getLogo() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public boolean hasSave() {
        return true;
    }

    @Override
    public LSaveFile getSave() {
        return save;
    }

    @Override
    public String getVersion() {
        return version;
    }

    @Override
    public ModListing getListing() {
        return new ModListing("Bashed Patch, SkyProc", false);
    }

    @Override
    public Mod getExportPatch() {
        Mod patch = new Mod(getListing());
        patch.setFlag(Mod.Mod_Flags.STRING_TABLED, false);
        patch.setAuthor("Pluto");
        return patch;
    }

    @Override
    public Color getHeaderColor() {
        return blue;
    }

    @Override
    public GRUP_TYPE[] dangerousRecordReport() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public JFrame openCustomMenu() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    //INI processing is done here.
    private void processINI() {
        SPProgressBarPlug.progress.setStatus("SkyBash: Processing INI");
        SPProgressBarPlug.progress.incrementBar();
        //Sets up the file reader for the ini file.
        INI ini = null;

        //Sets up the file reader for the ini file.
        try {
            ini = new INI("SkyBash.ini");
        } catch (IOException ex) {
            Logger.getLogger(SkyBash.class.getName()).log(Level.SEVERE, null, ex);
        }

        Collection<INI.IniSectionHead> sections = getSectionList();

        ini.addSection(sections);

        try {
            ini.readData();
        } catch (IOException ex) {
            Logger.getLogger(SkyBash.class.getName()).log(Level.SEVERE, null, ex);
        }

        initializeLists(ini);
    }

    //Grabs the lists of sections from the enum to be processed.
    private Collection<INI.IniSectionHead> getSectionList() {
        Collection<INI.IniSectionHead> sectionList = new ArrayList<>();

        for (IniSection currentSection : IniSection.values()) {
            sectionList.add(new INI.IniSectionHead(currentSection.getName(), currentSection.getFormat()));
        }

        return sectionList;
    }

    //Any storage lists are initialized from the INI here for ease of use.
    private void initializeLists(INI ini) {

        //Storage variable.
        ModListing m;

        try {
            ASISlanguage = ((ArrayList) ini.getCollection(new INI.IniSectionHead(IniSection.LANGUAGE.getName(),
                    IniSection.LANGUAGE.getFormat()))).get(0).toString().toLowerCase().replaceFirst(ASISlanguage.substring(0), ASISlanguage.substring(0).toUpperCase());
        } catch (Exception e) {
            ASISlanguage = "English";
        }

        settingsMap = ini.getMap(new INI.IniSectionHead(IniSection.SETTINGS.getName(),
                IniSection.SETTINGS.getFormat()));

        try {
            modTags = ini.getMap(new INI.IniSectionHead(IniSection.MODTAGS.getName(),
                    IniSection.MODTAGS.getFormat()));
            for (Map.Entry<String, String> entry : modTags.entrySet()) {
                m = new ModListing(entry.getKey());
                if (SPGlobal.getDB().hasMod(m)) {
                    mods.put(SPGlobal.getDB().getMod(m), new ModTags(entry.getValue()));
                }
            }
            SPGlobal.getDB().getMod(null);
        } catch (Exception e) {
        }

        try {
            debug = Boolean.parseBoolean((String) settingsMap.get("debug"));
        } catch (Exception e) {
        }
        try {
            memory = Integer.parseInt((String) (settingsMap.get("memory")));
        } catch (Exception e) {
        }
        try {
            masterlist = (String) (settingsMap.get("boss"));
        } catch (Exception e) {
        }
    }

    //Main patch changes are done here.
    @Override
    public void runChangesToPatch() throws Exception {
        processINI();
        if (save.getBool(GUISettings.PARSE_BOSS_LIST)) {
            processBossMasterlist();
        }
        if (save.getBool(GUISettings.DEBUG_LOGS)) {
            SPGlobal.loggingSync(true);
            SPGlobal.logging(true);
            SPGlobal.createGlobalLog();
            SPGlobal.debugModMerge = true;
        }

        /*
        SPDatabase base = new SPDatabase();
        Mod base = new Mod("Base", false);
        base.makeCopy(GRUP_TYPE.NPC_);
        */
        numSteps = SPGlobal.getDB().numMods() * 2 + 2;
        SPProgressBarPlug.progress.setMax(numSteps);
        SPProgressBarPlug.progress.setStatus(steps++, numSteps, "Initializing SkyBash");

        runMergers();
    }

    //Function used to run the mergers of GRUP's.
    public void runMergers() {
        if (save.getBool(GUISettings.SKYBASH_ON))  {
            if (save.getBool(GUISettings.MERGE_NPCS)) {
                SPProgressBarPlug.progress.setStatus("Processing NPC Merging");
                NPCMergerPatch nmerger = new NPCMergerPatch(mods);
                nmerger.mergeNPCs();
            }
            if (save.getBool(GUISettings.MERGE_WEAPONS)) {
                SPProgressBarPlug.progress.setStatus("Processing Weapon Merging");
                WeapMergerPatch wmerger = new WeapMergerPatch(mods);
                wmerger.mergeNPCs();
            }
            if (save.getBool(GUISettings.MERGE_RACES)) {
                SPProgressBarPlug.progress.setStatus("Processing Race Merging");
                RaceMergerPatch rmerger = new RaceMergerPatch(mods);
                rmerger.mergeRaces();
            }
            SPProgressBarPlug.progress.incrementBar();
        }
    }

    //List of ini sections to process and the format.
    private enum IniSection {

        LANGUAGE(INI.IniDataFormat.VALUE, "LANGUAGE"),
        SETTINGS(INI.IniDataFormat.KEY_VALUE, "SETTINGS"),
        MODTAGS(INI.IniDataFormat.KEY_VALUE, "MODTAGS"),
        MODEXCLUSIONS(INI.IniDataFormat.VALUE, "MODEXCLUSIONS");
        private INI.IniDataFormat format;
        private String name;

        IniSection(INI.IniDataFormat format, String name) {
            this.format = format;
            this.name = name;
        }

        String getName() {
            return name;
        }

        INI.IniDataFormat getFormat() {
            return format;
        }
    }

    //Function to return the mod, modTags map.
    public HashMap getModTagsMap() {
        return mods;
    }
    
    private void processBossMasterlist() {
        String currentLine;
        String nextLine;
        Scanner s;
        Mod temp;
        HashMap<String, Mod> modList;
        
        File f = new File(masterlist);
        if (f.isFile() && f.canRead()) {
            try {
                BufferedReader parser = new BufferedReader(new FileReader(f));
                try {
                    modList = new HashMap<>();
                    for (int i = 0; i < SPGlobal.getDB().numMods(); i++) {
                        temp = SPGlobal.getDB().getMod(i);
                        modList.put(temp.getName(), temp);
                    }
                    while ((currentLine = parser.readLine()) != null) {
                        if (modList.containsKey(currentLine.trim()) && !mods.containsKey(modList.get(currentLine))) {
                            nextLine = parser.readLine();
                            if (nextLine.contains("TAG:")) {
                                nextLine = nextLine.substring(nextLine.indexOf("BASH: ") + 6, nextLine.indexOf("}}"));
                                mods.put(modList.get(currentLine), new ModTags(nextLine));
                            }
                        }
                    }
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(null, "Invalid masterlist.  Please locate the BOSS masterlist and "
                    + "correct the entry in the SkyBash.ini appropriately.");
                    Logger.getLogger(SkyBash.class.getName()).log(Level.SEVERE, null, ex);
                }
            } catch (FileNotFoundException ex) {
                JOptionPane.showMessageDialog(null, "Invalid masterlist.  Please locate the BOSS masterlist and "
                    + "correct the entry in the SkyBash.ini appropriately.");
                Logger.getLogger(SkyBash.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            JOptionPane.showMessageDialog(null, "Invalid masterlist.  Please locate the BOSS masterlist and "
                    + "correct the entry in the SkyBash.ini appropriately.");
        }
    }
}
